package ch.ffhs.services;

import java.util.Timer;
import java.util.TimerTask;
import java.lang.Math;

import android.app.Service;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

/**
 * class MotionSensorService. Implements the sensor-listener for detecting
 * motion.
 * 
 * @author mf
 */
public class MotionSensorService extends Service implements SensorEventListener {
	private Integer timerPeriod;
	private Timer mTimer = null;
	private CountdownTimerTask sendCountdown = null;
	private Integer mTimecount = 0;
	private Integer mCountdown = 0;
	private Double mSensitivity = 0.05;
	private final IBinder mMotionSensorBinder = new MotionSensorBinder();
	private Handler mCallbackHandler;

	private SensorManager sensorManager;
	private Sensor sensor;

	public class MotionSensorBinder extends Binder {

		public void setCountdown(Integer timecount) {
			mTimecount = timecount;
			mCountdown = mTimecount;
			if (mCountdown > 0) {
				startTimer();
			}
		}

		public void setSensitivity(Integer sensitivity) {
			mSensitivity = (double) sensitivity / 100;
		}

		public void setCallbackHandler(final Handler callback) {
			mCallbackHandler = callback;
		}
	}

	private void resetCountdown() {
		//
		Log.d("MotionSensorService",
				"Reset countdown from " + mCountdown.toString() + " zu "
						+ mTimecount.toString());
		mCountdown = mTimecount;
	}

	private float[] mGravity;
	private Double mAccel;
	private Double mAccelCurrent;
	private Double mAccelLast;

	@Override
	public void onSensorChanged(SensorEvent event) {
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

			mGravity = event.values.clone();
			// motion detection
			Double x = (double) mGravity[0];
			Double y = (double) mGravity[1];
			Double z = (double) mGravity[2];
			mAccelLast = mAccelCurrent;
			mAccelCurrent = Math.sqrt(x * x + y * y + z * z);
			Double delta = mAccelCurrent - mAccelLast;
			mAccel = mAccel * 0.9 + delta;
			mAccel = Math.abs(mAccel);

			Log.d("MotionSensorService",
					"Sensor changed! Sensor: " + mAccel.toString());

			// sensor changed, reset timer
			if (mAccel > mSensitivity) {
				resetCountdown();
			}
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return mMotionSensorBinder;
	}

	public boolean onUnbind(Intent intent) {
		stopTimer();
		mCallbackHandler = null;
		return super.onUnbind(intent);
	}

	public void onCreate() {
		super.onCreate();
		Log.d("MotionSensorService", "onCreate");
		mTimer = new Timer("MotionSensorTimer");

		// create sensor
		sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
		sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

		mAccel = 0.00;
		mAccelCurrent = (double) SensorManager.GRAVITY_EARTH;
		mAccelLast = (double) SensorManager.GRAVITY_EARTH;

		if (ServiceManager.testMode) {
			timerPeriod = 1000;
		} else {
			timerPeriod = 1000 * 60;
		}
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d("MotionSensorService", "onStartCommand");
		
		startTimer();

		// register sensor listener
		sensorManager.registerListener(this, sensor,
				SensorManager.SENSOR_DELAY_NORMAL);
		
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		// unregister sensor listener
		sensorManager.unregisterListener(this);

		super.onDestroy();
	}

	private class CountdownTimerTask extends TimerTask {
		@Override
		public void run() {
			if (mCallbackHandler != null) {
				Log.d("CountdownTimerTask",
						"run - countdown: " + mCountdown.toString());
				if (mCountdown > 0) {
					mCountdown--;
					final Message msg = new Message();
					final Bundle bundle = new Bundle();
					bundle.putInt("Countdown", mCountdown);
					msg.setData(bundle);
					mCallbackHandler.sendMessage(msg);
				} else {
					stopTimer();
				}
			} else {
				Log.d("CountdownTimerTask", "run - no callback handler");
			}
		}
	}

	private void startTimer() {
		mTimer.cancel();
		mTimer = new Timer("MotionSensorTimer");
		sendCountdown = new CountdownTimerTask();
		mTimer.scheduleAtFixedRate(sendCountdown, 0, timerPeriod);
	}

	private void stopTimer() {
		mTimer.cancel();
	}

	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) {
	}
}